package util

import (
	"fmt"
	"github.com/jinzhu/copier"
	"reflect"

	"gopkg.in/yaml.v3"
)

type SearchOption map[string]any
type YAMLStructure []map[string]any

type StoreYAML struct {
	Search   SearchOption
	Original YAMLStructure
	Update   YAMLStructure
	Find     YAMLStructure
}

func searchFunction(key string, value any, s *StoreYAML) {
	for k, _ := range s.Search {
		if stringValue, ok := value.(string); ok {
			if stringValue == k {
				s.Find = append(s.Find, map[string]any{key: k})
			}
		}
		//switch k {
		//case string:
		//	if intValue, ok := value.(string); ok {
		//		if k == intValue {
		//			s.Find = append(s.Find, map[string]any{key: k})
		//		}
		//	}
		//case int:
		//	if intValue, ok := value.(int); ok {
		//		if k == intValue {
		//			s.Find = append(s.Find, map[string]any{key: k})
		//		}
		//	}
		//case bool:
		//	if intValue, ok := value.(bool); ok {
		//		if k == intValue {
		//			s.Find = append(s.Find, map[string]any{key: k})
		//		}
		//	}
		//}
	}
}

func updateFunction(key string, value any, s *StoreYAML) {
	for k, v := range s.Search {
		if stringValue, ok := value.(string); ok {
			if stringValue == k {
				copier.Copy(s.Update, s.Original)
				//fmt.Println(len(s.Update))
				s.Update[len(s.Update)] = map[string]any{key: v}
			}
		}
	}
}

func (s *StoreYAML) parse(key string, value any, function func(key string, value any, store *StoreYAML)) {
	switch valueType := value.(type) {
	case map[string]any:
		for k, v := range valueType {
			s.parse(k, v, function)
		}
	case []any:
		for _, v := range valueType {
			s.parse(key, v, function)
		}
	default:
		s.Original = append(s.Original, map[string]any{key: value})
		function(key, value, s)
	}
}

func Search(file string, searchKey SearchOption) StoreYAML {
	data := openFileToByte(file)
	value := make([]map[string]any, 0)
	store := StoreYAML{Search: searchKey, Original: value}

	var content map[string]any
	err := yaml.Unmarshal(data, &content)
	if err != nil {
		panic("unmarshal fail.")
	}

	for key, value := range content {
		store.parse(key, value, searchFunction)
	}

	return store
}

func Update(file string, searchOption SearchOption) StoreYAML {
	data := openFileToByte(file)
	value := make([]map[string]any, 0)
	store := StoreYAML{Search: searchOption, Original: value}

	var content map[string]any
	err := yaml.Unmarshal(data, &content)
	if err != nil {
		panic("unmarshal fail.")
	}

	for key, value := range content {
		store.parse(key, value, updateFunction)
	}

	return store
}

//func Update(search string, data any) {
//	value := reflect.ValueOf(data)
//	kind := value.Kind()
//
//	switch kind {
//	case reflect.Struct:
//		for i := 0; i < value.Elem().Len(); i++ {
//			//fmt.Println("struct")
//			Update(search, value.Index(i).Interface())
//		}
//	case reflect.Array, reflect.Slice:
//		for i := 0; i < value.Len(); i++ {
//			//fmt.Println("slice")
//			Update(search, value.Index(i).Interface())
//		}
//	case reflect.Map:
//		for _, key := range value.MapKeys() {
//			if value.MapIndex(key).Interface() == search {
//				fmt.Println("map >>> ", key, value.MapIndex(key))
//			} else {
//				//fmt.Println("map")
//				Update(search, value.MapIndex(key).Interface())
//			}
//		}
//	case reflect.String:
//		if value.String() == search {
//			fmt.Println("string >>> ", value)
//		}
//	case reflect.Int:
//		//fmt.Println(kind, Original.Interface())
//		i, _ := strconv.Atoi(search)
//		if value.Interface() == i {
//			fmt.Println("int >>> ", value)
//		}
//		//default:
//		//	fmt.Println("missing type is ", kind)
//	}
//}

func T(data interface{}) {
	value := reflect.ValueOf(data)
	k := value.Kind()
	//fmt.Println(k)
	// 检查数据类型
	switch k {
	case reflect.Struct:
		for i := 0; i < value.NumField(); i++ {
			field := value.Field(i)
			fmt.Printf("struct >>> %s: %v\n", field.Type().Name(), field.Interface())
			// 递归处理嵌套结构体
			T(field.Interface())
		}
	case reflect.Slice:
		for i := 0; i < value.Len(); i++ {
			fmt.Printf("slice >>> %s:\n", value.Index(i).Interface())
			// 递归处理切片元素
			T(value.Index(i).Interface())
		}
	//case reflect.String:
	//	fmt.Println("string >>> ", Original.Type().Name(), Original.Interface())
	case reflect.Map:
		fmt.Println("map >>> ", value.Type().Name(), value.Interface())
	}
}
